// C++模板详解：从基础到特化
// 模板是C++中非常强大的特性，允许您编写通用代码，适用于多种数据类型。让我从基础开始，逐步讲解模板的概念和用法。

// 1. 模板的基本概念
// 模板是一种代码复用机制，允许函数和类操作不同类型的数据，而不需要为每种类型重复编写代码。

// 为什么需要模板？
// 考虑这个问题：如果您想编写一个函数来查找数组中的最大值，您可能需要为不同类型编写多个版本：

// 整数版本
int findMax(int arr[], int n)
{
    int max = arr[0];
    for (int i = 1; i < n; i++)
        if (arr[i] > max)
            max = arr[i];
    return max;
}

// 浮点数版本
double findMax(double arr[], int n)
{
    double max = arr[0];
    for (int i = 1; i < n; i++)
        if (arr[i] > max)
            max = arr[i];
    return max;
}

template <typename T>
T findMax(T arr[], int n)
{
    T max = arr[0];
    for (int i = 1; i < n; i++)
        if (arr[i] > max)
            max = arr[i];
    return max;
}

// 2. 函数模板
// 基本语法
template <typename T> // 或 template <class T>
返回类型 函数名(参数列表)
{
    // 函数体
}

// 简单例子
template <typename T>
T add(T a, T b)
{
    return a + b;
}

// 使用
int sum1 = add<int>(5, 3);   // 显式指定类型
double sum2 = add(5.5, 3.7); // 编译器自动推导类型

// 多个类型参数
template <typename T1, typename T2>
auto multiply(T1 a, T2 b) -> decltype(a * b)
{
    return a * b;
}

// 使用
auto result = multiply(5, 3.5); // result类型为double

// 3. 类模板
// 基本语法
template <typename T>
class ClassName
{
    // 类定义
};

// 简单例子：通用数组类
template <typename T>
class Array
{
private:
    T *elements;
    int size;

public:
    Array(int s) : size(s)
    {
        elements = new T[size];
    }

    ~Array()
    {
        delete[] elements;
    }

    T &operator[](int index)
    {
        return elements[index];
    }

    int getSize() const
    {
        return size;
    }
};

// 使用
Array<int> intArray(10);           // 整数数组
Array<std::string> stringArray(5); // 字符串数组

// 类模板中的非类型参数
template <typename T, int Size>
class StaticArray
{
private:
    T elements[Size]; // 编译时确定大小

public:
    T &operator[](int index)
    {
        return elements[index];
    }

    int getSize() const
    {
        return Size;
    }
};

// 使用
StaticArray<int, 5> smallArray;
StaticArray<double, 1000> largeArray;

// 4. 模板特化
// 模板特化允许您为特定类型提供不同的实现。
// 为什么需要特化？
// 有时，通用模板对某些特定类型可能不是最优的，或者需要特殊处理。
// 函数模板特化
// 通用模板
template <typename T>
void print(T value)
{
    std::cout << value << std::endl;
}

// 为char*类型特化
template <>
void print<char *>(char *value)
{
    std::cout << "String: " << value << std::endl;
}

// 类模板特化

// 通用模板
template <typename T>
class Storage
{
private:
    T value;

public:
    Storage(T val) : value(val) {}
    void print() { std::cout << value << std::endl; }
};

// 为bool类型特化
template <>
class Storage<bool>
{
private:
    bool value;

public:
    Storage(bool val) : value(val) {}
    void print()
    {
        std::cout << (value ? "true" : "false") << std::endl;
    }
};

// 5. 部分特化
// 部分特化允许您为一组相关类型提供特殊实现。这只适用于类模板，不适用于函数模板。
// 通用模板
template <typename T, typename U>
class MyClass
{
    // 通用实现
};

// 部分特化：当第二个类型是int时
template <typename T>
class MyClass<T, int>
{
    // 特殊实现
};

// 例子：指针类型的部分特化
// 通用模板
template <typename T>
class SmartPointer
{
private:
    T *ptr;

public:
    SmartPointer(T *p) : ptr(p) {}
    ~SmartPointer() { delete ptr; }
    T &operator*() { return *ptr; }
};

// 为数组类型特化
template <typename T>
class SmartPointer<T[]>
{
private:
    T *ptr;

public:
    SmartPointer(T *p) : ptr(p) {}
    ~SmartPointer() { delete[] ptr; } // 使用delete[]
    T &operator[](int index) { return ptr[index]; }
};

// 6. 模板特化的实际应用：std::hash
// 现在让我们回到您最初的问题，理解std::hash的特化。
// std::hash的基本结构
namespace std
{
    // 通用模板声明（没有默认实现）
    template <typename T>
    struct hash;

    // 为int特化
    template <>
    struct hash<int>
    {
        size_t operator()(int val) const
        {
            return static_cast<size_t>(val);
        }
    };

    // 为string特化
    template <>
    struct hash<string>
    {
        size_t operator()(const string &val) const
        {
            // 字符串哈希算法实现
            // ...
        }
    };

    // 更多内置类型的特化...
}

// 为自定义类型特化std::hash
class Customer
{
public:
    Customer(int id, std::string name) : id(id), name(name) {}

    int getId() const { return id; }
    std::string getName() const { return name; }

    bool operator==(const Customer &other) const
    {
        return id == other.id && name == other.name;
    }

private:
    int id;
    std::string name;
};

// 在std命名空间中特化hash模板
namespace std
{
    template <> // 完全特化这里的template <>表示这是一个完全特化，不再有类型参数。hash<Customer>指定我们正在为Customer类型特化hash模板。
    struct hash<Customer>
    { // 为Customer类型特化
        size_t operator()(const Customer &c) const
        {
            // 组合现有的哈希函数
            return hash<int>()(c.getId()) ^
                   (hash<string>()(c.getName()) << 1);
        }
    };
}

// 7. 模板实例化过程
// 理解模板如何工作的关键是理解实例化过程：

// 1.编写模板：您定义一个通用模板
// 2.使用模板：您使用特定类型调用模板
// 3.实例化：编译器生成该特定类型的代码版本
// 4.编译和链接：生成的代码被编译和链接